home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / System / HotKeys / HotKeys.c next >
Encoding:
C/C++ Source or Header  |  1993-11-30  |  7.4 KB  |  372 lines  |  [TEXT/KAHL]

  1. /*
  2.  *    File:        HotKeys.c
  3.  *
  4.  *    Abstract:    Implements both the low level and GUI of hot keys.
  5.  *
  6.  *    Licensing:    This code may be used without fees provided that proper
  7.  *                copyright notice given.
  8.  *
  9.  *    History:    1.0.0    RSM        93-11-29    Created first version
  10.  *
  11.  *    ©1993 One Step Beyond
  12.  */
  13.  
  14. #ifdef THINK_C
  15. #    include <MacHeaders>
  16. #else
  17. #    include <Dialogs.h>
  18. #    include <Memory.h>
  19. #    include <Resources.h>
  20. #    include <ToolUtils.h>
  21. #endif
  22. #include <Script.h>
  23. #include "HotKeys.h"
  24.  
  25.  
  26. /*
  27.  *    Constants
  28.  */
  29. #define kSicnBytes        32                // # of bytes per SICN
  30. #define kSicnSize        16                // pixel height and width
  31. #define modFlagsMask    (cmdKey+shiftKey+optionKey+controlKey)
  32.  
  33.  
  34. /*
  35.  *    Some quicky types
  36.  */
  37. typedef unsigned char    uchar;
  38.  
  39.  
  40. /*
  41.  *    Static data
  42.  */
  43. static uchar sicnKeys[] = {    0x37, 0x38, 0x3A, 0x3B,        // cmd, shift, opt, cntrl 
  44.                             0x7D, 0x7E, 0x7B, 0x7C,     // arrows (left, right, down, up)
  45.                             0x33, 0x75,                 // del, fwd del
  46.                             0xFF };
  47.                               
  48. static uchar strKeys[] =  { 0x35, 0x24, 0x4C, 0x30, 0x31, 0x47, // esc, ret, ent, tab, space, clear 
  49.                             0x72, 0x73, 0x74, 0x77, 0x79,        // help, home, pg up, end, pg down, 
  50.                             0x7A, 0x78, 0x63, 0x76, 0x60,        // F1-F5
  51.                             0x61, 0x62, 0x64, 0x65, 0x6D,        // F6-F10
  52.                             0x67, 0x6F, 0x69, 0x6B, 0x71,        // F9-F15
  53.                             0xFF };
  54.  
  55. static uchar numKPadKeys[] = { 0x41, 0x43, 0x45, 0x4B, 0x4E, 0x51, 0x52, 0x53,  
  56.                                0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5B, 0x5C,
  57.                                0xFF };
  58.  
  59. /*
  60.  *    Local function prototypes
  61.  */
  62.  
  63. static short DrawModifiers( const Rect*, const Handle, const short );
  64. static void DrawSicnKey( const HotKey*, const Rect*, const Handle, const short );
  65. static void DrawStrKey( const HotKey*, const Rect* );
  66. static void PlotSICN( const Rect*, const short, const Handle );
  67. static short KeyCodeToAscii( const short );
  68. static short ToUpper( const short );
  69. static short InBytes( const short, const uchar* );
  70.  
  71.  
  72. /*
  73.  *    Global variables
  74.  */
  75. short gHotKeySICNRsrcID    = 1024;
  76. short gHotKeyDLOGRsrcID = 1024;
  77. short gHotKeyStrsRsrcID = 1024;
  78.  
  79.  
  80. /*
  81.  *    return 1 if the msg & mods match the given hotkey, 0 otherwise
  82.  */
  83. short 
  84. IsHotKey( const HotKey *key, 
  85.           const long msg, 
  86.           const short mods )
  87. {
  88.     uchar    keyCode = (msg & keyCodeMask) >> 8;
  89.     uchar    modFlags = (mods & modFlagsMask) >> 8;
  90.     
  91.     return key->onOff && ( key->mods == modFlags ) && ( key->keyCode == keyCode );
  92. }
  93.  
  94.  
  95. /*
  96.  *    Set the given hotkey given the msg and mods
  97.  */
  98. void 
  99. SetHotKey( HotKey *key, 
  100.            const long msg, 
  101.            const short mods )
  102. {
  103.     key->onOff = 1;
  104.     key->filler = 0;
  105.     key->mods = (mods & modFlagsMask) >> 8;
  106.     key->keyCode = (msg & keyCodeMask) >> 8;
  107. }
  108.  
  109.  
  110. /*
  111.  *    Unsets a hot key to nothing.
  112.  */
  113. void 
  114. ClearHotKey( HotKey *key )
  115. {
  116.     key->onOff = 0;
  117. }
  118.  
  119.  
  120. /*
  121.  *    Set's the hot key using a "modal" dialog.
  122.  */
  123. void
  124. SetHotKeyDlog( HotKey *key )
  125. {
  126.     GrafPtr            savePort;
  127.     DialogPtr        dp;
  128.     EventRecord        evt;
  129.     unsigned long    wait;
  130.     Handle            ihdl;
  131.     Rect            irect;
  132.     short            itype;
  133.     
  134.     GetPort( &savePort );
  135.     dp = GetNewDialog( gHotKeyDLOGRsrcID, NULL, (GrafPtr)-1L );
  136.     if( dp ){
  137.         SetPort( dp );
  138.         DrawDialog( dp );
  139.         GetDItem( dp, 2, &itype, &ihdl, &irect );
  140.         FrameRect( &irect );
  141.  
  142.         do{
  143.             WaitNextEvent( everyEvent, &evt, 300, NULL );
  144.         }while( !(evt.what == mouseDown || evt.what == keyDown) );
  145.         
  146.         if( evt.what == keyDown ){
  147.             SetHotKey( key, evt.message, evt.modifiers );
  148.             InsetRect( &irect, 1, 1 );
  149.             DrawHotKey( key, &irect );
  150.     
  151.             wait = TickCount() + 30;
  152.             while( wait > TickCount() )
  153.                 WaitNextEvent( 0, &evt, 6, NULL );
  154.         }
  155.  
  156.         DisposeDialog( dp );
  157.     }
  158.     SetPort( savePort );
  159. }
  160.  
  161.  
  162. /*
  163.  *    Draw the hot key's representation in the current port.
  164.  *    Note: this uses's the port's current font, size, face and colors
  165.  */
  166. OSErr
  167. DrawHotKey( const HotKey *key, 
  168.             const Rect *bnds )
  169. {
  170.     RgnHandle    saveClip;
  171.     Handle        sicnH;
  172.     Rect        r;
  173.     short        idx;
  174.     OSErr        err;
  175.     uchar        ascii;
  176.     
  177.     if( key->onOff == 0 )
  178.         return noErr;
  179.             
  180.     if( (saveClip = NewRgn()) == NULL )
  181.         return MemError();
  182.  
  183.     if( (sicnH = GetResource( 'SICN', gHotKeySICNRsrcID )) == NULL )
  184.         return ResError();
  185.         
  186.     GetClip( saveClip );
  187.     ClipRect( bnds );
  188.  
  189.     r = *bnds;
  190.     r.left = DrawModifiers( &r, sicnH, key->mods );
  191.  
  192.     if( idx = InBytes( key->keyCode, sicnKeys ) )
  193.         DrawSicnKey( key, &r, sicnH, idx );
  194.     else
  195.         DrawStrKey( key, &r );
  196.  
  197.     SetClip( saveClip );
  198.     DisposeRgn( saveClip );
  199.     return noErr;
  200. }
  201.  
  202.  
  203. /*
  204.  *    Draw the modifier keys by bit shifting throught the modifier field flags.
  205.  *    If the bit is set, draw the cooresponding SICN.  Does not change the pen 
  206.  *    location.
  207.  *    Returns the right horizontal position after the last icon drawn.
  208.  */
  209. static short
  210. DrawModifiers( const Rect *bnds, 
  211.                const Handle sicnH,
  212.                const short mods )
  213. {
  214.     Rect    r;
  215.     short    idx, mask;
  216.     
  217.     r.left = bnds->left + 1;
  218.     r.top = bnds->top + ((bnds->bottom - bnds->top) - kSicnSize) / 2;
  219.     r.right = r.left + kSicnSize;
  220.     r.bottom = r.top + kSicnSize;
  221.     
  222.     idx = 1;
  223.     mask = 0x01;
  224.     do{    
  225.         if( mask & mods ){
  226.             PlotSICN( &r, idx, sicnH );
  227.             OffsetRect( &r, 12, 0 );
  228.         }
  229.         idx++;
  230.         mask <<= 1;
  231.         if( mask == 0x04 )        // Skip the caps lock
  232.             mask <<= 1;
  233.     }while( !(mask & 0x80) );
  234.  
  235.     return r.left;
  236. }
  237.  
  238.  
  239. /*
  240.  *
  241.  */
  242. static void
  243. DrawSicnKey( const HotKey *key, 
  244.              const Rect *bnds, 
  245.              const Handle sicnH,
  246.              const short idx )
  247. {
  248.     Rect    r;
  249.         
  250.     r.left = bnds->left + 2;
  251.     r.top = bnds->top + ((bnds->bottom - bnds->top)-kSicnSize) / 2;
  252.     r.right = r.left + kSicnSize; 
  253.     r.bottom = r.top + kSicnSize;
  254.     LoadResource( sicnH );
  255.     PlotSICN( &r, idx, sicnH );
  256. }
  257.  
  258.  
  259. /*
  260.  *
  261.  */
  262. static void
  263. DrawStrKey( const HotKey *key, 
  264.             const Rect *bnds )
  265. {
  266.     Str32    s;
  267.     GrafPtr    port;
  268.     short    fontSize, height, idx;
  269.     uchar    ascii;
  270.     
  271.     if( InBytes( key->keyCode, numKPadKeys ) ){
  272.         s[0] = 3;
  273.         s[1] = '[';
  274.         s[2] = ascii;
  275.         s[3] = ']';
  276.     }else if( idx = InBytes( key->keyCode, strKeys ) ){
  277.         GetIndString( s, gHotKeyStrsRsrcID, idx );
  278.     }else{
  279.         ascii = KeyCodeToAscii( key->keyCode );
  280.         if( ascii != -1 ){
  281.             s[0] = 1;
  282.             s[1] = (ascii>='a' && ascii<='z') ? (ascii-'a'+'A') : ascii;
  283.         }else{
  284.             s[0] = 4;
  285.             s[1] = '(';
  286.             s[2] = s[3] = '?';
  287.             s[4] = ')';
  288.         }
  289.     }
  290.     
  291.     GetPort( &port );
  292.     height = bnds->bottom - bnds->top;
  293.     fontSize = port->txSize ? port->txSize : 12;
  294.     
  295.     MoveTo( bnds->left + 2, bnds->bottom - ((height-fontSize)/2) - 2 );
  296.     DrawString( s );
  297. }
  298.  
  299.  
  300. /*
  301.  *    Convert a virtual keycode to it's cooresponding ASCII code using the 'KCHR'
  302.  *    resource.  This code is adapted from the "kcapApp" snippet by Greg Robbins
  303.  *    of Apple DTS.
  304.  */
  305. static short 
  306. KeyCodeToAscii( const short keyCode )
  307. {
  308.     Handle    kchrH;
  309.     long    state;
  310.     short    kchrID;
  311.     uchar    ascii;
  312.     
  313.     kchrID = GetScript( GetEnvirons(smKeyScript), smScriptKeys );
  314.     kchrH = RGetResource( 'KCHR', kchrID );
  315.     if( kchrH == NULL )
  316.         return -1;
  317.     
  318.     state = 0;
  319.     ascii = KeyTrans( *kchrH, keyCode, &state );
  320.     
  321.     if( HomeResFile( kchrH ) > 1 )
  322.         ReleaseResource( kchrH );
  323.     
  324.     return ascii;
  325. }
  326.  
  327.  
  328. /*
  329.  *    Return the position (one based) in the given array of unsigned chars of the 
  330.  *    given code.
  331.  *    Note: similar to the function strchr() in string.h.
  332.  */
  333. static short
  334. InBytes( const short code, const uchar *kp )
  335. {
  336.     short idx = 1;
  337.  
  338.     do{
  339.         if( *kp == code ){
  340.             return idx;
  341.         }else{
  342.             kp++;
  343.             idx++;
  344.         }
  345.     }while( *kp != 0xFF );
  346.     return 0;
  347. }
  348.  
  349.  
  350. /*
  351.  *    Utility routing to plot a SICN.  The idx is one (1) based.
  352.  */
  353. static void 
  354. PlotSICN( const Rect *bnds, 
  355.           const short idx, 
  356.           const Handle sicnH )
  357. {
  358.     BitMap    bm;
  359.     char    hstate;
  360.     
  361.     hstate = HGetState( sicnH );
  362.     HLock( sicnH );
  363.     bm.baseAddr = *sicnH + (idx-1) * kSicnBytes;
  364.     bm.rowBytes = kSicnBytes / kSicnSize;
  365.     bm.bounds.top = bm.bounds.left = 0;
  366.     bm.bounds.bottom = bm.bounds.right = kSicnSize;
  367.  
  368.     StdBits( &bm, &bm.bounds, bnds, srcCopy, NULL );
  369.     HSetState( sicnH, hstate );
  370. }
  371.  
  372.